﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;

namespace LooseChart
{
    public abstract class ISeries : FrameworkElement
    {
        #region 绘制内容
        protected DrawingVisual DV { get; set; } = new DrawingVisual();
        protected override int VisualChildrenCount => 1;
        protected override Visual GetVisualChild(int index) { return DV; }
        #endregion

        public ISeries()
        {
            this.AddVisualChild(DV);
            this.RenderTransform = new MatrixTransform();
            this.Loaded += (sender, e) => { this.Redraw(); };
        }

        #region 轴
        /// <summary>
        /// x轴
        /// </summary>
        public IAxis XAxis
        {
            get { return (IAxis)GetValue(XAxisProperty); }
            set { SetValue(XAxisProperty, value); }
        }
        public static readonly DependencyProperty XAxisProperty = DependencyProperty.Register("XAxis", typeof(IAxis), typeof(ISeries), new PropertyMetadata(null, (d, e) =>
        {
            if (d is ISeries series)
            {
                if (e.OldValue is IAxis o && o != null)
                {
                    o.AxisChanged -= series.Redraw;
                    o.AxisMoved -= series.MoveX;
                }
                if (e.NewValue is IAxis n && n != null)
                {
                    n.AxisChanged += series.Redraw;
                    n.AxisMoved += series.MoveX;
                }
                series.Redraw();
            }
        }));
        /// <summary>
        /// y轴
        /// </summary>
        public IAxis YAxis
        {
            get { return (IAxis)GetValue(YAxisProperty); }
            set { SetValue(YAxisProperty, value); }
        }
        public static readonly DependencyProperty YAxisProperty = DependencyProperty.Register("YAxis", typeof(IAxis), typeof(ISeries), new PropertyMetadata(null, (d, e) =>
        {
            if (d is ISeries series)
            {
                if (e.OldValue is IAxis o && o != null)
                {
                    o.AxisChanged -= series.Redraw;
                    o.AxisMoved -= series.MoveY;
                }
                if (e.NewValue is IAxis n && n != null)
                {
                    n.AxisChanged += series.Redraw;
                    n.AxisMoved += series.MoveY;
                }
                series.Redraw();
            }
        }));
        #endregion

        #region 数据
        /// <summary>
        /// x数据源
        /// </summary>
        public IList XSource
        {
            get { return (IList)GetValue(XSourceProperty); }
            set { SetValue(XSourceProperty, value); }
        }
        public static readonly DependencyProperty XSourceProperty = DependencyProperty.Register("XSource", typeof(IList), typeof(ISeries), new PropertyMetadata(null, (d, e) => { if (d is ISeries series) series.Redraw(); }));
        /// <summary>
        /// y数据源
        /// </summary>
        public IList YSource
        {
            get { return (IList)GetValue(YSourceProperty); }
            set { SetValue(YSourceProperty, value); }
        }
        public static readonly DependencyProperty YSourceProperty = DependencyProperty.Register("YSource", typeof(IList), typeof(ISeries), new PropertyMetadata(null, (d, e) => { if (d is ISeries series) series.Redraw(); }));

        private Func<object, double> xSourceConverter = DefaultConverter;
        /// <summary>
        /// x值转换方法
        /// </summary>
        public Func<object, double> XSourceConverter { get { return xSourceConverter; } set { xSourceConverter = value; Redraw(); } }

        private Func<object, double> ySourceConverter = DefaultConverter;
        /// <summary>
        /// y值转换方法
        /// </summary>
        public Func<object, double> YSourceConverter { get { return ySourceConverter; } set { ySourceConverter = value; Redraw(); } }

        private static double DefaultConverter(object o)
        {
            return Convert.ToDouble(o);
        }
        #endregion

        #region 性能
        /// <summary>
        /// 计算图形的for循环时允许的最大并发线程数量
        /// </summary>
        public int MaxDegreeOfParallelism
        {
            get { return (int)GetValue(MaxDegreeOfParallelismProperty); }
            set { SetValue(MaxDegreeOfParallelismProperty, value); }
        }
        public static readonly DependencyProperty MaxDegreeOfParallelismProperty = DependencyProperty.Register("MaxDegreeOfParallelism", typeof(int), typeof(ISeries), new PropertyMetadata(4));

        internal CancellationTokenSource CancelTokenSource { get; set; }
        /// <summary>
        /// 是否正在绘制图形
        /// </summary>
        public bool IsDrawing { get { return CancelTokenSource != null && !CancelTokenSource.IsCancellationRequested; } }
        /// <summary>
        /// 取消绘制
        /// </summary>
        public void CancelDrawing()
        {
            if (CancelTokenSource != null && !CancelTokenSource.IsCancellationRequested) CancelTokenSource.Cancel();
        }
        #endregion

        #region 外观
        /// <summary>
        /// 是否显示填充色
        /// </summary>
        public bool ShowFill
        {
            get { return (bool)GetValue(ShowFillProperty); }
            set { SetValue(ShowFillProperty, value); }
        }
        public static readonly DependencyProperty ShowFillProperty = DependencyProperty.Register("ShowFill", typeof(bool), typeof(ISeries), new PropertyMetadata(true, (d, e) => { if (d is ISeries series) series.Reshow(); }));
        /// <summary>
        /// 是否显示边框色
        /// </summary>
        public bool ShowStroke
        {
            get { return (bool)GetValue(ShowStrokeProperty); }
            set { SetValue(ShowStrokeProperty, value); }
        }
        public static readonly DependencyProperty ShowStrokeProperty = DependencyProperty.Register("ShowStroke", typeof(bool), typeof(ISeries), new PropertyMetadata(true, (d, e) => { if (d is ISeries series) series.Reshow(); }));

        /// <summary>
        /// 虚线样式
        /// </summary>
        public DashStyle DashStyle
        {
            get { return (DashStyle)GetValue(DashStyleProperty); }
            set { SetValue(DashStyleProperty, value); }
        }
        public static readonly DependencyProperty DashStyleProperty = DependencyProperty.Register("DashStyle", typeof(DashStyle), typeof(ISeries), new PropertyMetadata(DashStyles.Solid));

        /// <summary>
        /// 边框粗细
        /// </summary>
        public int StrokeThickness
        {
            get { return (int)GetValue(StrokeThicknessProperty); }
            set { SetValue(StrokeThicknessProperty, value); }
        }
        public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register("StrokeThickness", typeof(int), typeof(ISeries), new PropertyMetadata(1, (d, e) => { if (d is ISeries series) series.Reshow(); }));

        private const byte DefaultA = 0xff;
        /// <summary>
        /// 填充色不透明度
        /// </summary>
        public byte FillColorA
        {
            get { return (byte)GetValue(FillColorAProperty); }
            set { SetValue(FillColorAProperty, value); }
        }
        public static readonly DependencyProperty FillColorAProperty = DependencyProperty.Register("FillColorA", typeof(byte), typeof(ISeries), new PropertyMetadata(DefaultA, (d, e) => { if (d is ISeries series) series.Reshow(); }));
        /// <summary>
        /// 边框色不透明度
        /// </summary>
        public byte StrokeColorA
        {
            get { return (byte)GetValue(StrokeColorAProperty); }
            set { SetValue(StrokeColorAProperty, value); }
        }
        public static readonly DependencyProperty StrokeColorAProperty = DependencyProperty.Register("StrokeColorA", typeof(byte), typeof(ISeries), new PropertyMetadata(DefaultA, (d, e) => { if (d is ISeries series) series.Reshow(); }));

        /// <summary>
        /// 超出界限部分在边缘显示
        /// </summary>
        public bool ExcessDisplayAtEdge
        {
            get { return (bool)GetValue(ExcessDisplayAtEdgeProperty); }
            set { SetValue(ExcessDisplayAtEdgeProperty, value); }
        }
        public static readonly DependencyProperty ExcessDisplayAtEdgeProperty = DependencyProperty.Register("ExcessDisplayAtEdge", typeof(bool), typeof(ISeries), new PropertyMetadata(false, (d, e) => { if (d is ISeries series) series.Redraw(); }));

        /// <summary>
        /// 显示的颜色
        /// </summary>
        public Color DisplayColor
        {
            get { return (Color)GetValue(DisplayColorProperty); }
            set { SetValue(DisplayColorProperty, value); }
        }
        public static readonly DependencyProperty DisplayColorProperty = DependencyProperty.Register("DisplayColor", typeof(Color), typeof(ISeries), new PropertyMetadata(Colors.Black, (d, e) => { if (d is ISeries series) series.Reshow(); }));

        static readonly Random random = new Random();
        /// <summary>
        /// 随机一个新颜色值
        /// </summary>
        /// <returns></returns>
        public static Color RandomColor(byte a = 0xff)
        {
            byte r = Convert.ToByte(random.Next(255));
            byte g = Convert.ToByte(random.Next(255));
            byte b = Convert.ToByte(random.Next(255));
            return new Color() { A = a, R = r, G = g, B = b };
        }

        /// <summary>
        /// 获取伪彩渐变色
        /// </summary>
        /// <param name="i">当前梯度值</param>
        /// <param name="max">最大梯度量</param>
        /// <param name="baseColor">基础颜色</param>
        /// <returns></returns>
        public static Color GetGradientColor(long i, long max, Color baseColor)
        {
            var tempv = 240 * i / max;
            var r = baseColor.R;
            var g = baseColor.G;
            var b = baseColor.B;
            var hsb = RGBToHSB(r, g, b);
            var rgb = HSBToRGB(hsb.Item1 - tempv, 1, 1);
            return Color.FromRgb(rgb.Item1, rgb.Item2, rgb.Item3);
        }
        /// <summary>
        /// HSB转RGB值
        /// </summary>
        /// <param name="hue">色相</param>
        /// <param name="saturation">饱和度</param>
        /// <param name="brightness">亮度</param>
        /// <returns>RGB值</returns>
        public static Tuple<byte, byte, byte> HSBToRGB(double hue, double saturation, double brightness)
        {
            while (hue < 0) hue += 360;
            while (hue > 360) hue -= 360;
            if (hue == 360) hue = 0;
            double r = 0;
            double g = 0;
            double b = 0;
            if (saturation == 0) { r = g = b = Convert.ToByte(brightness % byte.MaxValue); }
            else
            {
                double sectorPos = hue / 60d;
                int sectorNum = (int)Math.Floor(sectorPos);
                double fractionalSector = sectorPos - sectorNum;
                double p = brightness * (1 - saturation);
                double q = brightness * (1 - (saturation * fractionalSector));
                double t = brightness * (1 - (saturation * (1 - fractionalSector)));
                switch (sectorNum)
                {
                    case 0: r = brightness; g = t; b = p; break;
                    case 1: r = q; g = brightness; b = p; break;
                    case 2: r = p; g = brightness; b = t; break;
                    case 3: r = p; g = q; b = brightness; break;
                    case 4: r = t; g = p; b = brightness; break;
                    case 5: r = brightness; g = p; b = q; break;
                }
            }
            return new Tuple<byte, byte, byte>(Convert.ToByte(r * byte.MaxValue), Convert.ToByte(g * byte.MaxValue), Convert.ToByte(b * byte.MaxValue));
        }
        /// <summary>
        /// RGB转HSB
        /// </summary>
        /// <param name="red"></param>
        /// <param name="green"></param>
        /// <param name="blue"></param>
        /// <returns></returns>
        public static Tuple<double, double, double> RGBToHSB(byte red, byte green, byte blue)
        {
            double h = 0, s = 0, b = 0;
            double max = Math.Max(red, Math.Max(green, blue));
            if (max <= 0) return new Tuple<double, double, double>(h, s, b);
            double min = Math.Min(red, Math.Min(green, blue));
            double dif = max - min;
            if (max > min)
            {
                if (green == max) h = (blue - red) / dif * 60d + 120d;
                else if (blue == max) h = (red - green) / dif * 60d + 240d;
                else if (blue > green) h = (green - blue) / dif * 60d + 360d;
                else h = (green - blue) / dif * 60d;
                if (h < 0) h = h + 360d;
            }
            else h = 0;
            s = dif / max;
            b = max / 255d;
            return new Tuple<double, double, double>(h, s, b);
        }
        #endregion

        #region 显示图形
        /// <summary>
        /// 主要的显示图形的矢量数据流
        /// </summary>
        internal List<StreamGeometry> MainGeometry { get; set; }
        /// <summary>
        /// 绘制图形，全部重新生成矢量数据并绘制
        /// </summary>
        public virtual async void Redraw()
        {
            if (!IsLoaded || XAxis == null || YAxis == null || !XAxis.IsLoaded || !YAxis.IsLoaded) return;
            await this.UpdateChartDataStream();
            this.Reshow();
        }
        /// <summary>
        /// 重新显示矢量图形
        /// </summary>
        internal abstract void Reshow();
        /// <summary>
        /// 绘制内容
        /// </summary>
        /// <param name="color">基础颜色</param>
        /// <param name="list">矢量数据流</param>
        /// <param name="dc">画布</param>
        protected abstract void DrawDrawingContext(Color color, List<StreamGeometry> list, DrawingContext dc);
        /// <summary>
        /// 更新数据源的统计信息
        /// </summary>
        /// <param name="chartDataSource">数据源</param>
        /// <param name="gateArea">门区域，为空表示总数据</param>
        /// <returns></returns>
        protected abstract Task UpdateStatisticsData(CancellationToken token);
        /// <summary>
        /// 获取数据源的矢量数据流
        /// </summary>
        /// <param name="chartDataSource">数据源</param>
        /// <returns></returns>
        protected abstract Task UpdateStreamGeometry(CancellationToken token);
        /// <summary>
        /// 刷新图
        /// </summary>
        /// <returns></returns>
        internal virtual async Task UpdateChartDataStream()
        {
            try
            {
                if (CancelTokenSource != null && !CancelTokenSource.IsCancellationRequested) CancelTokenSource.Cancel();
                var token = CancelTokenSource = new CancellationTokenSource();
                var tk = token.Token;
                await UpdateStatisticsData(tk);
                if (!tk.IsCancellationRequested) await UpdateStreamGeometry(tk);
                if (!tk.IsCancellationRequested)
                {
                    token.Cancel();
                    token.Dispose();
                }
            }
            catch (TaskCanceledException) { }
        }

        /// <summary>
        /// x方向移动
        /// </summary>
        /// <param name="d"></param>
        internal virtual void MoveX(double d)
        {
            if (this.RenderTransform is MatrixTransform matrixTransform)
            {
                var matrix = matrixTransform.Matrix;
                matrixTransform.Matrix = new Matrix(1, 0, 0, 1, matrix.OffsetX + d, matrix.OffsetY);
            }
        }
        /// <summary>
        /// y方向移动
        /// </summary>
        /// <param name="d"></param>
        internal virtual void MoveY(double d)
        {
            if (this.RenderTransform is MatrixTransform matrixTransform)
            {
                var matrix = matrixTransform.Matrix;
                matrixTransform.Matrix = new Matrix(1, 0, 0, 1, matrix.OffsetX, matrix.OffsetY + d);
            }
        }

        /// <summary>
        /// 清除图形转换
        /// </summary>
        internal virtual void ClearTransform()
        {
            if (this.RenderTransform is MatrixTransform matrixTransform && matrixTransform.Matrix != default)
            {
                matrixTransform.Matrix = new Matrix();
            }
        }
        #endregion
    }
}
